package com.liuchuanzheng.lcz_wanandroid.module.home.viewmodel

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.jeremyliao.liveeventbus.LiveEventBus
import com.kingja.loadsir.callback.Callback
import com.kingja.loadsir.callback.SuccessCallback
import com.liuchuanzheng.lcz_wanandroid.R
import com.liuchuanzheng.lcz_wanandroid.base.BaseViewModel
import com.liuchuanzheng.lcz_wanandroid.ext.showToast
import com.liuchuanzheng.lcz_wanandroid.module.common.bus.CollectStatusEvent
import com.liuchuanzheng.lcz_wanandroid.module.common.bus.LoginStatusEvent
import com.liuchuanzheng.lcz_wanandroid.module.common.callback.ErrorCallback
import com.liuchuanzheng.lcz_wanandroid.module.home.bean.Article
import com.liuchuanzheng.lcz_wanandroid.module.home.repository.ArticleRepository
import com.liuchuanzheng.lcz_wanandroid.module.home.repository.CollectRepository
import com.liuchuanzheng.lcz_wanandroid.module.user.UserManager
import com.liuchuanzheng.lcz_wanandroid.net.base.PageBean
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.async
import kotlinx.coroutines.launch

/**
 * @author 刘传政
 * @date 2021/9/14 0014 18:20
 * QQ:1052374416
 * 电话:18501231486
 * 作用:
 * 注意事项:
 */
class ArticleViewModel : BaseViewModel() {


    //<editor-fold defaultstate="collapsed" desc="被外部观察的变量">
    // 上下两个标签包起来,是为了让它默认收起,并且在structure窗口查看是,有中文提示,
    // 并且结构整洁.并且此标签可以多层次嵌套,让你随心设置代码结构.此处只是为了试验效果.
    // 你可以用到你自己想用的地方
    val articleList: MutableLiveData<ArticleListPageBean> = MutableLiveData()
    val smartRefreshStatus: MutableLiveData<Boolean> = MutableLiveData() //下拉刷新控件的状态
    val smartLoaMoreStatus: MutableLiveData<Boolean> = MutableLiveData() //上拉加载控件的状态
    val liveData_loadServiceStatus: MutableLiveData<Class<out Callback>> = MutableLiveData() //loadsir的状态
    val liveData_loading = MutableLiveData<Boolean>()
    //</editor-fold>
    private val articleRepository by lazy { ArticleRepository() }
    private val collectRepository by lazy { CollectRepository() }
    var pageBean: PageBean = PageBean()
    fun getArticles(isRefresh: Boolean) {
        //将置顶文章直接组合到文章列表。只在刷新时请求指定文章

        //由于这里有两个协程同时启动。采用普通的try catch 是不管用的。现象是抓不住异常，而程序崩溃
        //要使用CoroutineExceptionHandler处理错误。因为涉及到协程的结构化并发（我也不太懂）
        val exceptionHandler = CoroutineExceptionHandler { _, exception ->
            exception.printStackTrace()
            showToast(R.string.network_not_available)
            liveData_loadServiceStatus.value = ErrorCallback::class.java
            smartRefreshStatus.value = false
            smartLoaMoreStatus.value = false
        }
        viewModelScope.launch(exceptionHandler) {

            if (isRefresh) {
                var topResultDeferred = async {
                    articleRepository.getTopArticleList()
                }
                var articleResultDeferred = async {
                    articleRepository.getArticleList(pageBean.serverFirstPage)
                }
                var topResult = topResultDeferred.await()
                var articleResult = articleResultDeferred.await()
                if (topResult.isServerResultOK() && articleResult.isServerResultOK()) {
                    //标记为置顶
                    topResult.data!!.forEach {
                        it.top = true
                    }
                    var addall = (topResult.data!! + articleResult.data!!.datas).toMutableList()
                    var articleListPageBean = ArticleListPageBean()
                    articleListPageBean.articleList = addall
                    articleListPageBean.isRefresh = isRefresh
                    pageBean.resetDefault()
                    articleList.value = articleListPageBean
                    //让分页bean加一页。这必须是网络有结果后判断后再进行加一页。有的人请求时就加一页了，你想想对吗？加载更多失败了，再来一次加载更多，那不就又加一页？
                    pageBean.addCurrentPage()
                }

            } else {
                var articleResult = articleRepository.getArticleList(pageBean.currentPage + 1)
                if (articleResult.isServerResultOK()) {
                    var articleListPageBean = ArticleListPageBean()
                    articleListPageBean.articleList = articleResult.data!!.datas
                    articleListPageBean.isRefresh = isRefresh
                    articleList.value = articleListPageBean
                    //让分页bean加一页。这必须是网络有结果后判断后再进行加一页。有的人请求时就加一页了，你想想对吗？加载更多失败了，再来一次加载更多，那不就又加一页？
                    pageBean.addCurrentPage()
                }

            }

            liveData_loadServiceStatus.value = SuccessCallback::class.java //页面根据自己的情况去显示success或empty
            smartRefreshStatus.value = false
            smartLoaMoreStatus.value = false

        }

    }
    fun collect(id: Long) {
        liveData_loading.value = true
        launch(
            workBlock = {
                var result = collectRepository.collect(id)
                handleResult(result,
                    successBlock = {
                        showToast("收藏成功")
                        val event = CollectStatusEvent(id,true)
                        LiveEventBus.get(CollectStatusEvent::class.java).post(event)
                    },
                    failBlock = {
                        showToast("${result.errorMsg}")
                    }
                )
            }, errorBlock = {
                showToast(R.string.network_not_available)
            }, finillyBlock = {
                liveData_loading.value = false
            }
        )
    }

    fun uncollect(id: Long) {
        liveData_loading.value = true
        launch(
            workBlock = {
                var result = collectRepository.uncollect(id)
                handleResult(result,
                    successBlock = {
                        showToast("已取消收藏")
                        val event = CollectStatusEvent(id,false)
                        LiveEventBus.get(CollectStatusEvent::class.java).post(event)
                    },
                    failBlock = {
                        showToast("${result.errorMsg}")
                    }
                )
            }, errorBlock = {
                showToast(R.string.network_not_available)
            }, finillyBlock = {
                liveData_loading.value = false
            }
        )
    }

    /**
     * 这是为了结果能带一些透传参数，view方便有不同的显示效果
     * 比如刷新操作异常，如果本来有数据，那就没必要显示空白页;而本来没数据就显示空白页
     * 所以我是反对网络接口的操作进行统一处理的，比如出错就显示toast。有的接口本来就是不同view条件下，有不同的错误提示。否则效果会让用户很反感。
     * @property page Int
     * @property articleList MutableList<Article>?
     */
    class ArticleListPageBean {
        var isRefresh: Boolean = true
        var articleList: MutableList<Article>? = null
    }

}